﻿using System;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;

namespace Rainr.EFClient
{
    /// <summary>
    /// 查询序列扩展
    /// </summary>
    public static class IQueryableExtensions
    {
        /// <summary>
        /// 根据键按升序对序列的元素排序。
        /// </summary>
        /// <typeparam name="TSource">source 中的元素的类型。</typeparam>
        /// <param name="source"> 一个要排序的值序列。</param>
        /// <param name="sortField">排序字段</param>
        /// <param name="sortOrder">排序顺序[asc|desc]</param>
        /// <returns>一个 System.Linq.IOrderedEnumerable，其元素按键排序。</returns>
        public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string sortField, string sortOrder) where TSource : class
        {
            if (string.IsNullOrEmpty(sortOrder)
                ||
                sortOrder.Equals("asc", StringComparison.OrdinalIgnoreCase)
                )
            {
                return OrderBy<TSource>(source, sortField);
            }
            return OrderByDescending<TSource>(source, sortField);
        }
        /// <summary>
        /// 根据键按升序对序列的元素排序。
        /// </summary>
        /// <typeparam name="TSource">source 中的元素的类型。</typeparam>
        /// <param name="source"> 一个要排序的值序列。</param>
        /// <param name="propertyName">一个排序的对象属性。</param>
        /// <returns>一个 System.Linq.IOrderedEnumerable，其元素按键排序。</returns>
        public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName) where TSource : class
        {
            Type type = typeof(TSource);
            PropertyInfo property = type.GetProperty(propertyName);
            ParameterExpression param = Expression.Parameter(type, "p");
            Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
            LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
            return source.Provider.CreateQuery<TSource>(resultExp);
        }
        /// <summary>
        /// 根据键按降序对序列的元素排序。
        /// </summary>
        /// <typeparam name="TSource">source 中的元素的类型。</typeparam>
        /// <param name="source">一个要排序的值序列。</param>
        /// <param name="propertyName">一个排序的对象属性。</param>
        /// <returns>一个 System.Linq.IOrderedEnumerable，将根据键按降序对其元素进行排序。</returns>
        public static IQueryable<TSource> OrderByDescending<TSource>(this IQueryable<TSource> source, string propertyName) where TSource : class
        {
            Type type = typeof(TSource);
            PropertyInfo property = type.GetProperty(propertyName);
            ParameterExpression param = Expression.Parameter(type, "p");
            Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
            LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
            return source.Provider.CreateQuery<TSource>(resultExp);
        }
        
        /// <summary>
        /// 对一个延迟查询已排序完成的序列元素进行分页。
        /// </summary>
        /// <typeparam name="TSource">source 中的元素的类型。</typeparam>
        /// <param name="source">一个要分页的值序列。</param>
        /// <param name="pageIndex">页位置。</param>
        /// <param name="pageSize">页大小。</param>
        /// <param name="rowTotal">分页前行总数。</param>
        /// <returns>一个已分页的元素序列。</returns>
        public static IQueryable<TSource> Pagination<TSource>(this IQueryable<TSource> source, int pageIndex, int pageSize, out int rowTotal) where TSource : class
        {
            rowTotal = source.Count();
            return source.Skip<TSource>(pageIndex < 1 ? 0 : ((pageIndex - 1) * pageSize)).Take<TSource>(pageSize);
        }
    }
}
